/**
 * Copyright (C) 2010-2016 eBusiness Information, Excilys Group
 * Copyright (C) 2016-2020 the AndroidAnnotations project
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed To in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ohosannotations.internal.process;

import org.ohosannotations.logger.Logger;
import org.ohosannotations.logger.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * TimeStats
 *
 * @since 2021-07-20
 */
public class TimeStats {
    private static final Logger LOGGER = LoggerFactory.getLogger(TimeStats.class);
    private final Map<String, Long> measures = new HashMap<>();
    private final List<Duration> durations = new ArrayList<>();

    /**
     * Duration
     *
     * @since 2021-07-20
     */
    private static class Duration implements Comparable<Duration> {
        /**
         * 关键
         */
        private final String key;
        /**
         * 时间
         */
        private final long durationInMs;

        /**
         * 持续时间
         *
         * @param key 关键
         * @param durationInMs 时间
         */
        Duration(String key, long durationInMs) {
            this.key = key;
            this.durationInMs = durationInMs;
        }

        @Override
        public int compareTo(Duration duration) {
            return (int) (duration.durationInMs - durationInMs);
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
            Duration duration = (Duration) obj;
            return durationInMs == duration.durationInMs && Objects.equals(key, duration.key);
        }

        @Override
        public int hashCode() {
            return Objects.hash(key, durationInMs);
        }
    }

    /**
     * start
     *
     * @param key 键
     */
    public void start(String key) {
        long start = System.currentTimeMillis();
        measures.put(key, start);
    }

    /**
     * stop
     *
     * @param key key
     */
    public void stop(String key) {
        Long start = measures.remove(key);
        if (start != null) {
            long end = System.currentTimeMillis();
            long duration = end - start;
            durations.add(new Duration(key, duration));
        }
    }

    /**
     * toString
     *
     * @return sb
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Time measurements: ");

        Collections.sort(durations);
        for (Duration duration : durations) {
            sb.append("[") //
                .append(duration.key) //
                .append(" = ") //
                .append(duration.durationInMs) //
                .append(" ms], ");
        }

        return sb.toString();
    }

    /**
     * logStats
     */
    public void logStats() {
        LOGGER.info(toString());
    }

    /**
     * clear
     */
    public void clear() {
        measures.clear();
        durations.clear();
    }
}
